home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Applications / Graphics / Gnuplot / Source / FunctionObject.m < prev    next >
Encoding:
Text File  |  1993-03-18  |  7.8 KB  |  400 lines

  1.  
  2. static char RCSId[]="$Id: FunctionObject.m,v 1.1.1.1 1993/03/18 03:33:14 davis Exp $";
  3.  
  4.  
  5. #import "FunctionObject.h"
  6.  
  7. #import <sys/stat.h>        /* stat()            */
  8. #import <sys/types.h>        /* stat()            */
  9.  
  10. #import <objc/hashtable.h>    /* NXCopyStringBufferFromZone()    */
  11. #import <objc/zone.h>
  12.  
  13. #import <ctype.h>        /* isspace()            */
  14. #import <libc.h>        /* index(), rindex()        */
  15.  
  16.  
  17. const char *styleString[] = {"lines", "points", "linespoints", "dots",
  18.                  "impulses", "errorbars", "boxes", "boxerrorbars"};
  19.  
  20.  
  21. /*  Is the string blank (i.e. full of only white space)?  */
  22. static BOOL _isBlank (const char *aString)
  23. {
  24.     const char *cur;
  25.  
  26.     for (cur = aString ; *cur != '\0' ; cur++)
  27.     if (*cur != ' ' && *cur != '\t' && *cur != '\n')
  28.         return NO;
  29.  
  30.     return YES;
  31. }
  32.  
  33.  
  34. static BOOL _isSpaceNotNL (char aChar)
  35. {
  36.     return (isspace (aChar)) && (aChar != '\n');
  37. }
  38.  
  39.  
  40.  
  41.  
  42. /*  
  43.  *  aString is assumed to be a one-line string (i.e it contains no 
  44.  *  newlines).  This could be changed easily if need be.
  45.  */
  46. static void _removeComments (char *aString)
  47. {
  48.     char *cur = aString;
  49.     char quote[100];
  50.     int number = 0;
  51.  
  52.     while (*cur) {
  53.     if ((*cur == '\'') || (*cur == '"')) {
  54.  
  55.         /*  
  56.          *  The quote is either closing a previous quotation or 
  57.          *  starting a new one.  We look at the last quote 
  58.          *  encountered to see which.
  59.          */
  60.         if (number && (*cur == quote[number - 1]))    /* closing previous */
  61.         number--;
  62.         else                    /* starting new        */
  63.         quote[number++] = *cur;
  64.  
  65.     } else if (number && (*cur == '#')) {
  66.  
  67.         /*  
  68.          *  If we've encountered a pound sign outside of a 
  69.          *  quotation, we've found a comment.  The rest of the 
  70.          *  line can be truncated.
  71.          */
  72.         cur = '\0';
  73.  
  74.     }
  75.  
  76.     cur++;
  77.     }
  78.  
  79. }
  80.  
  81.  
  82. static void _getWith (char *aString, int *style, int *lineStyle,
  83.               int *pointsStyle)
  84. {
  85.     char *cur, *with;
  86.  
  87.     /* 
  88.      *  This attempts to detect a 'with' phrase and to extract the 
  89.      *  style from it if it exists.  There are several ways to trick 
  90.      *  this. 
  91.      */
  92.     if ((with = rindex (aString, 'w')) && (*(with+1) == 'i') &&
  93.     (cur = index (with, ' '))) {
  94.     switch (*(++cur)) {
  95.     case 'p':  *style = FUNCTION_POINTS;    break;
  96.     case 'd':  *style = FUNCTION_DOTS;    break;
  97.     case 'i':  *style = FUNCTION_IMPULSES;    break;
  98.     case 'e':  *style = FUNCTION_ERRORBARS;    break;
  99.     case 'b':
  100.         if (index (cur, 'r')) *style = FUNCTION_BOXERRORBARS;
  101.         else *style = FUNCTION_BOXES;
  102.         break;
  103.     case 'l':
  104.         if (index (cur, 'p')) *style = FUNCTION_LINESPOINTS;
  105.         else *style = FUNCTION_LINES;
  106.         break;
  107.     default:   *style = FUNCTION_NOSTYLE;    break;
  108.     }
  109.     *with = '\0';
  110.  
  111.     /* 
  112.      *  If the style type includes lines or points, the user has 
  113.      *  the option of setting the point/line styles.  Check for 
  114.      *  those...
  115.      */
  116.                         /* Line Style */
  117.     if ((*style == FUNCTION_POINTS) || (*style == FUNCTION_LINES) ||
  118.         (*style == FUNCTION_LINESPOINTS)) {
  119.  
  120.         while (cur && *cur && ((*cur > '6') || (*cur < '1')))
  121.         cur++;
  122.         if (cur && *cur)
  123.         *lineStyle = *cur - '0';
  124.  
  125.                         /* Point Style */
  126.         if ((*style == FUNCTION_POINTS) ||
  127.         (*style == FUNCTION_LINESPOINTS))  {
  128.  
  129.         while (cur && *cur && ((*cur > '6') || (*cur < '1')))
  130.             cur++;
  131.         if (cur && *cur)
  132.             *pointsStyle = *cur - '0';
  133.         }
  134.  
  135.     }
  136.  
  137.     }
  138.  
  139. }
  140.  
  141.  
  142.  
  143.  
  144. static char *_getTitle (char *aString)
  145. {
  146.     while (aString && *aString) {
  147.  
  148.     /*
  149.      *  If this appears to be a "title" phrase, see if a quoted
  150.      *  string follows.  If one does, chop it off and return it.
  151.      */
  152.     
  153.     if ((*aString == 't') &&
  154.         ((*(aString + 1) == 'i') || _isSpaceNotNL (*(aString + 1)))) {
  155.  
  156.         char *firstQuote, *beginning = aString;
  157.  
  158.         while (!_isSpaceNotNL (*aString))
  159.         aString++;
  160.         while (_isSpaceNotNL (*aString))
  161.         aString++;
  162.         if ((*aString == '\'') || (*aString == '"')) {
  163.  
  164.         /*  
  165.          *  Okay, we are as sure as can be that this is a 
  166.          *  "title" phrase.
  167.          */
  168.         firstQuote = aString;
  169.         if (aString = index (++aString, *firstQuote))
  170.             *aString = '\0';
  171.         *beginning = '\0';
  172.  
  173.         return ++firstQuote;
  174.         }
  175.  
  176.     }
  177.  
  178.     aString++;
  179.     }
  180.  
  181.     return NULL;
  182. }
  183.  
  184.  
  185. @implementation FunctionObject
  186.  
  187.  
  188. /*  Does the string contain something besides white space?  */
  189. + (BOOL) isAcceptableStringValue:(const char *)aString
  190. {
  191.     return (aString && !_isBlank (aString));
  192.     /* todo, also check for valid functions, if possible */
  193. }
  194.     
  195.  
  196. /*  
  197.  *  Makes sure the file whose full path is specified by aString is a 
  198.  *  regular, readable file.
  199.  */
  200. + (BOOL) isAcceptableDataFile:(const char *)aString
  201. {
  202.     struct stat fileinfo;
  203.     BOOL returnVal;
  204.  
  205.     returnVal = (aString && !stat (aString, &fileinfo) &&
  206.          ((fileinfo.st_mode & S_IFMT) == S_IFREG) &&
  207.          (fileinfo.st_mode & S_IREAD));
  208.     return returnVal;
  209. }
  210.  
  211.  
  212.  
  213. /*  
  214.  *  The attributes of a function are stored by an instance of 
  215.  *  FunctionObject.  The only complicated part is parsing those 
  216.  *  attributes from a Gnuplot "plot" statement.  aString should 
  217.  *  specify only the part of that statement pertaining to the function 
  218.  *  that will be stored by this instance and should contain no leading 
  219.  *  white space.  (This method could be nicer by ignoring leading 
  220.  *  white space.)
  221.  */
  222. - initFromString:(const char *)aString
  223. {
  224.     char quote, *cur;
  225.     NXZone *zone;
  226.  
  227.     [super init];
  228.  
  229.     zone = [self zone];
  230.  
  231.     title = NULL;            /* Defaults */
  232.     style = FUNCTION_NOSTYLE;
  233.     pointsStyle = POINTS_NOSTYLE;
  234.     lineStyle = LINE_NOSTYLE;
  235.     isDataFile = NO;
  236.  
  237.     if (aString)  {
  238.  
  239.     stringValue = NXCopyStringBufferFromZone (aString, zone);
  240.     _removeComments (stringValue);
  241.     _getWith (stringValue, &style, &lineStyle, &pointsStyle);
  242.     [self setTitle:_getTitle (stringValue)];
  243.  
  244.     /* 
  245.      *  If this string value is quoted, it is a data file.  We 
  246.      *  remove the quotes and set the isDataFile flag.  The string 
  247.      *  is assumed to have no leading white space, i.e. if it is a 
  248.      *  data file, the first character is a quote.
  249.      */
  250.  
  251.     quote = *stringValue;
  252.     if ((quote == '\'') || (quote == '"')) {   /* This is a data file */
  253.  
  254.         isDataFile = YES;
  255.         *rindex (stringValue, quote) = '\0';
  256.         cur = NXCopyStringBufferFromZone (stringValue+1, zone);
  257.         NXZoneFree (zone, stringValue);
  258.         stringValue = cur;
  259.  
  260.     } else {        /* This is a function, not a data file. */
  261.  
  262.         /* Remove trailing blanks */
  263.         cur = stringValue + strlen (stringValue) - 1 ;
  264.         while (isspace (*cur) && (cur >= stringValue))
  265.         *(cur--) = '\0';
  266.  
  267.     }
  268.  
  269.     } else
  270.     stringValue = NULL;
  271.       
  272.   return self;
  273. }
  274.  
  275.  
  276. - free
  277. {
  278.     NXZoneFree ([self zone], title);
  279.  
  280.     return [super free];
  281. }
  282.  
  283.  
  284. - setDataFile:(BOOL)cond
  285. {
  286.     isDataFile = cond;
  287.     return self;
  288. }
  289.  
  290.  
  291. - (BOOL)isDataFile
  292. {
  293.     return isDataFile;
  294. }
  295.  
  296.  
  297. - setTitle:(const char *)aString
  298. {
  299.     char *aux;
  300.     NXZone *zone = [self zone];
  301.  
  302.     NXZoneFree (zone, title);
  303.     if (aString) {
  304.  
  305.     title = NXCopyStringBufferFromZone (aString, zone);
  306.  
  307.     /* 
  308.      *  Make sure aString doesn't mix both kinds of quotation marks.  
  309.      *  Gnuplot can handle one or the other but not both in one title. 
  310.      *  (If there's a mix, use double quotation marks.)
  311.      */
  312.  
  313.     if ( (index (title, '"')) && (aux = index (title, '\'')) ) {
  314.         do
  315.         *aux = '"';
  316.         while (aux = index (title, '\''));
  317.     }
  318.  
  319.     } else
  320.     title = NULL;
  321.  
  322.     return self;
  323. }
  324.  
  325.  
  326. - (const char *)title
  327. {
  328.     return title;
  329. }
  330.  
  331.  
  332. - setStyle:(int) anInt
  333. {
  334.     style = anInt;
  335.     return self;
  336. }
  337.  
  338.  
  339. - (int)style
  340. {
  341.     return style;
  342. }
  343.  
  344.  
  345. - (const char *)styleString
  346. {
  347.     if (style == FUNCTION_NOSTYLE)
  348.     return NULL;
  349.     else
  350.     return styleString[style];
  351. }
  352.  
  353.  
  354. - setPointsStyle: (int)anInt
  355. {
  356.     pointsStyle = anInt;
  357.     return self;
  358. }
  359.  
  360.  
  361. - (int)pointsStyle
  362. {
  363.     return pointsStyle;
  364. }
  365.  
  366.  
  367. - setLineStyle: (int)anInt
  368. {
  369.     lineStyle = anInt;
  370.     return self;
  371. }
  372.  
  373.  
  374. - (int)lineStyle
  375. {
  376.     return lineStyle;
  377. }
  378.  
  379.  
  380.  
  381. /*  
  382.  *  If the function is actually a data file, it is similar to an 
  383.  *  attachment, or a "file link," so we return YES.  If the function 
  384.  *  is not a data file, we return NO.
  385.  */
  386. - (BOOL)isAttachment
  387. {
  388.     return isDataFile;
  389. }
  390.  
  391.  
  392. // Shuts up the compiler about unused RCSId
  393. - (const char *) rcsid
  394. {
  395.     return RCSId;
  396. }
  397.  
  398.  
  399. @end
  400.